//-----------------------------------------------------------------------------
// Bend2D - Physics Engine 
// Test Ambient
// 11/03/2010
// Roberto Bender <beto.bender@gmail.com>
//-----------------------------------------------------------------------------
#include <cstdlib>
#include <GL/glut.h>
#include <iostream>

#include "bend2d.h"
#include "myworld.h"
#include "mywindpoint.h"
#include "myobjectcreator.h"
#include "mydurableresetter.h"
#include "benchmarking.h"

using namespace bend2d;
using namespace std;

World * myworld = NULL;
//-----------------------------------------------------------------------------
// Open GL Render Scene
//-----------------------------------------------------------------------------
void renderScene(void) 
{
    glClearColor(1, 1, 1, 0);
    glClear(GL_COLOR_BUFFER_BIT);

    myworld->Draw();
#ifdef BEND2D_DEBUG
	myworld->DrawNew();
#endif
    glutSwapBuffers();
}

double fireiteration = 0.0001;
double iterations = fireiteration;
double iterationstep = 100000;
int points = 0;
int maxpoints = 200;

bool iterate = false;
bool autoiterate = false;

void idleFunc(void)
{
    StopWatch sit;
    StopWatch sait;
    StopWatch sr;
    
    sit.Start();

    if(iterate || autoiterate)
    {
        iterate = false;
        //myworld->Iterate(myworld->GetTimeSinceLastIteration());
        myworld->Iterate(1);
        iterations += iterationstep;

        if(iterations >= fireiteration && points++ < maxpoints)
        {
            iterations = 0;
            WindPoint * wpoint = Factory::GetInstance()->AccessObjectCreator()->CreateWindPoint(Point(10, 245), Speed(10000,Angle(45)), Acceleration());
            myworld->RegistryObject(wpoint);
        }
    }
    sit.Stop();

    sait.Start();
    if(autoiterate)
        myworld->Iterated();
    sait.Stop();

    sr.Start();
    renderScene();
    sr.Stop();
}

void mouse (int button, int state, int x, int y)
{
    if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
    {
        myworld->Iterated();
        iterate = true;
    }

    if(button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
    {
        autoiterate = !autoiterate;
    }

    if(button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN)
    {
        maxpoints += 100;
    }


}

class magnetic : public PhysicForce
{
public:

    Point Center;
    Acceleration customAcc;

    magnetic()
    {
      Center = Point(rand()%640,rand()%480);
        customAcc.SetMag(rand()%20);
    }

	void ApplyPhysics(Physicable* object)
	{
		Moveable* mv = dynamic_cast<Moveable*>(object);
		if(mv)
		{
            customAcc = Acceleration(Center - mv->GetPosition());
			object->ApplyForce(customAcc);
		}
	}
};

int main(int argc, char* argv[])
{
    Factory::GetInstance()->RegistryObjectCreator(new myObjectCreator());
    bend2d::Rectangle worldBounds(Point(320, 240), Angle(0), 640, 480);
    myworld = new myWorld(worldBounds);

    myworld->Enable(World::eTwoStepsIteration);
    myworld->RegistryPhysicForce(Factory::GetInstance()->AccessObjectCreator()->CreatePhysicForce("Gravity"));

    double xi=0, yi=0;
    for(double x = 0; x < 640; x+=20)
    {
        double y = rand() % 200;
        myworld->RegistryObject(Factory::GetInstance()->AccessObjectCreator()->CreateBoundary(Line(xi,yi,x+20,y)));
        yi = y;
        xi = x + 20;
    }

    /*WindPoint * alonePoint1 = Factory::GetInstance()->AccessObjectCreator()->CreateWindPoint(Point(640/4, 480/2), Speed(12,Angle(45)), Acceleration(50, Angle(45)));
    WindPoint * alonePoint2 = Factory::GetInstance()->AccessObjectCreator()->CreateWindPoint(Point(640 - 640/4, 480/2), Speed(), Acceleration(12, Angle(90+45)));

    myDurableResetter * resetter = new myDurableResetter;
    alonePoint1->SetDurableResetter(resetter);
    alonePoint1->SetTimeSense(true, 0.0001);

    alonePoint2->SetDurableResetter(resetter);
    alonePoint2->SetTimeSense(true, 0.002);

    myworld->RegistryObject(alonePoint1);
    myworld->RegistryObject(alonePoint2);
    
    for(int i = 0; i < 10; ++i)
    {
        WindPoint * point = Factory::GetInstance()->AccessObjectCreator()->CreateWindPoint(Point(rand()%640, rand()%480), Speed(1,Angle(rand()%360)), Acceleration(rand()%5, Angle(rand()%360)));
        point->SetDurableResetter(resetter);
        point->SetIterationSense(true, rand()%500 + 1);
        point->SetFriction(10);
        myworld->RegistryObject(point);
    }*/
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowSize(320,240);
    glutCreateWindow("Boucing BEND2D");

    gluOrtho2D(myworld->GetBoundary().GetLeft() - 20, myworld->GetBoundary().GetRight() + 20, myworld->GetBoundary().GetBottom() - 20, myworld->GetBoundary().GetTop() + 20);

    // Misc //
    glEnable(GL_POINT_SMOOTH);
	glEnable(GL_LINE_SMOOTH);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glutDisplayFunc(renderScene);
    glutIdleFunc(idleFunc);
    glutMouseFunc(mouse);
    glutMainLoop();
    return 0;
}

